package com.duck.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.duck.base.oauth.jwt.filter.JwtAuthenticationTokenFilter;
import com.duck.base.oauth.security.DuckAccessDecisionManager;
import com.duck.base.oauth.security.handler.DuckAccessDeniedHandler;
import com.duck.base.oauth.security.handler.DuckAuthenticationFailureHandler;
import com.duck.base.oauth.security.handler.DuckAuthenticationSuccessHandler;
import com.duck.base.oauth.security.handler.DuckLogoutSuccessHandler;
import com.duck.base.oauth.security.handler.DuckUrlValidateHandler;
import com.duck.base.oauth.security.properties.UrlRule;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private UserDetailsService duckUserDetailService;
	@Autowired
	private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
	@Autowired
	private DuckAuthenticationSuccessHandler duckAuthenticationSuccessHandler;
	@Autowired
	private DuckAuthenticationFailureHandler duckAuthenticationFailureHandler;
	@Autowired
	private DuckLogoutSuccessHandler duckLogoutSuccessHandler;
	@Autowired
	private DuckAccessDeniedHandler duckAccessDeniedHandler;
	@Autowired
	private UrlRule urlRule;
	
	@Autowired
	public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
		authenticationManagerBuilder
				// 设置UserDetailsService
				.userDetailsService(duckUserDetailService)
				// 使用BCrypt进行密码的hash
				.passwordEncoder(new BCryptPasswordEncoder());
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<>();
		DuckUrlValidateHandler urlValidateHandler = new DuckUrlValidateHandler(urlRule);
    	voters.add(urlValidateHandler);
    	DuckAccessDecisionManager duckAccessDecisionManager= new DuckAccessDecisionManager(voters);
		http
		.csrf().disable()
		.httpBasic()
		.and()
		.authorizeRequests()
		.accessDecisionManager(duckAccessDecisionManager)
		.anyRequest()
		.authenticated()
		.and()
		.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
		.exceptionHandling().accessDeniedHandler(duckAccessDeniedHandler)
		.and()
		.formLogin()
		.successHandler(duckAuthenticationSuccessHandler)
		.failureHandler(duckAuthenticationFailureHandler)
		.permitAll()
		.and()
		.logout()
		.logoutSuccessHandler(duckLogoutSuccessHandler)
		;
	}

}
